package com.feng.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.feng.common.utils.Asserts;
import com.feng.common.utils.FileUtil;
import com.feng.common.utils.RedisCache;
import com.feng.common.utils.SecurityUtil;
import com.feng.mbg.domain.*;
import com.feng.mbg.mapper.SysRoleMapper;
import com.feng.mbg.mapper.SysUserMapper;
import com.feng.mbg.mapper.SysUsersRolesMapper;
import com.feng.security.config.SecurityConst;
import com.feng.security.domain.LoginUser;
import com.feng.system.dao.SysRoleDao;
import com.feng.system.dao.SysUserDao;
import com.feng.system.dto.UserParam;
import com.feng.system.dto.UserQueryParam;
import com.feng.system.service.UserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

/**
 * @author Feng
 * @since 2022/4/15 12:23
 */

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    SysUserMapper userMapper;

    @Autowired
    SysRoleMapper roleMapper;

    @Autowired
    SysUsersRolesMapper usersRolesMapper;

    @Autowired
    SysRoleDao roleDao;

    @Autowired
    SysUserDao userDao;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    RedisCache redisCache;

    @Override
    public List<SysRole> getRolesById(Long id) {
        return roleDao.selectByUserId(id);
    }

    @Override
    public void addUser(UserParam userParam) {

        // 用户名 和 昵称 不能重复
        if (getUserByUsername(userParam.getUsername()) != null) {
            Asserts.fail("该用户名已存在");
        }
        if (getUserByNickname(userParam.getNickName()) != null) {
            Asserts.fail("该昵称已存在");
        }

        Set<Long> roleIds = userParam.getRoleIds();
        Integer isAdmin = userParam.getIsAdmin();
        // 若要为新管理用户分配角色
        if (CollectionUtil.isNotEmpty(roleIds)) {
            if (isAdmin.equals(0)) {
                Asserts.fail("不能为非管理用户分配角色");
            }
            int currentRoleLevel = SecurityUtil.getCurrentRoleLevel();
            for (Long roleId : roleIds) {
                SysRole role = roleMapper.selectByPrimaryKey(roleId);
                if (role == null || role.getIsDeleted().equals(1)) {
                    Asserts.fail("ID为" + roleId + "的角色不存在");
                }
                if (currentRoleLevel > role.getLevel()) {
                    Asserts.fail("禁止添加等级高于自己的用户");
                }
            }
        }

        SysUser user = new SysUser();
        user.setUsername(userParam.getUsername());
        user.setPassword(passwordEncoder.encode("123456"));
        user.setIsAdmin(isAdmin);
        user.setIsEnabled(userParam.getIsEnabled());
        user.setGender(userParam.getGender());
        user.setNickName(userParam.getNickName());
        user.setPhone(userParam.getPhone());
        user.setEmail(userParam.getEmail());
        user.setAvatar(userParam.getAvatar());
        user.setCreateTime(new Date());
        userMapper.insertSelective(user);

        // 分配角色
        if (CollectionUtil.isNotEmpty(roleIds)) {
            Long userId = getUserByUsername(userParam.getUsername()).getUserId();
            for (Long roleId : roleIds) {
                SysUsersRoles sysUsersRoles = new SysUsersRoles();
                sysUsersRoles.setUserId(userId);
                sysUsersRoles.setRoleId(roleId);
                usersRolesMapper.insert(sysUsersRoles);
            }
        }
    }

    @Override
    public void updateUser(UserParam userParam) {

        Long userId = userParam.getUserId();
        SysUser user = userMapper.selectByPrimaryKey(userId);

        if (user == null || user.getIsDeleted().equals(1)) {
            Asserts.fail("修改的用户不存在");
        }

        Integer userRawLevel = roleDao.selectMinLevelByUserId(userId);
        int currentLevel = SecurityUtil.getCurrentRoleLevel();
        if (userRawLevel != null && currentLevel > userRawLevel) {
            Asserts.fail("不可修改角色等级高于自己的用户");
        }

        if (!StrUtil.equals(userParam.getNickName(), user.getNickName()) && getUserByNickname(userParam.getNickName()) != null) {
            // 修改为已存在的昵称
            Asserts.fail("该昵称已存在");
        }

        if (userParam.getIsEnabled().equals(0) && user.getDisabledable().equals(0)) {
            // 若禁用不可禁用的用户
            Asserts.fail("该用户不可禁用");
        }

        Set<Long> newRoleIds = userParam.getRoleIds();
        for (Long newRoleId : newRoleIds) {
            SysRole role = roleMapper.selectByPrimaryKey(newRoleId);
            if (role == null || role.getIsDeleted().equals(1)) {
                Asserts.fail("ID为" + newRoleId + "的角色不存在");
            }
            if (currentLevel > role.getLevel()) {
                Asserts.fail("不可为用户分配等级高于自己的角色");
            }
        }

        // 修改用户信息
        user.setIsEnabled(userParam.getIsEnabled());
        user.setGender(userParam.getGender());
        user.setNickName(userParam.getNickName());
        user.setPhone(userParam.getPhone());
        user.setEmail(userParam.getEmail());
        user.setAvatar(userParam.getAvatar());
        user.setUpdateTime(new Date());
        userMapper.updateByPrimaryKey(user);

        // 删除该用户原有角色
        SysUsersRolesExample deleteRolesExample = new SysUsersRolesExample();
        deleteRolesExample.createCriteria().andUserIdEqualTo(userId);
        usersRolesMapper.deleteByExample(deleteRolesExample);
        // 分配角色
        roleDao.insertRolesByUserId(userId, newRoleIds);
    }

    @Override
    public void deleteUser(Set<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return;
        }
        int currentLevel = SecurityUtil.getCurrentRoleLevel();
        for (Long id : ids) {
            SysUser user = userMapper.selectByPrimaryKey(id);
            if (user == null || user.getIsDeleted().equals(1)) {
                continue;
            }
            if (user.getDeletable().equals(0)) {
                Asserts.fail("用户" + user.getUsername() + "不能删除");
            }
            Integer level = roleDao.selectMinLevelByUserId(user.getUserId());
            if (level != null && currentLevel > level) {
                Asserts.fail("无法删除权限等级高于自己的用户");
            }
        }
        SysUserExample userExample = new SysUserExample();
        userExample.createCriteria().andUserIdIn(new ArrayList<>(ids));
        SysUser user = new SysUser();
        user.setIsDeleted(1);
        userMapper.updateByExampleSelective(user, userExample);
    }

    @Override
    public PageInfo<SysUser> search(UserQueryParam param, Integer pageNum, Integer pageSize) {

        String keyWord = param.getKeyWord();
        Integer isAdmin = param.getIsAdmin();
        Integer isEnabled = param.getIsEnabled();

        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo<>(userDao.selectByQueryParam(keyWord, isAdmin, isEnabled));
    }

    private SysUser getUserByUsername(String username) {
        SysUserExample userExample = new SysUserExample();
        userExample.createCriteria().andIsDeletedEqualTo(0).andUsernameEqualTo(username);
        List<SysUser> users = userMapper.selectByExample(userExample);
        if (users.isEmpty()) {
            return null;
        }
        return users.get(0);
    }

    private SysUser getUserByNickname(String nickname) {
        if (nickname == null) {
            return null;
        }
        SysUserExample userExample = new SysUserExample();
        userExample.createCriteria().andIsDeletedEqualTo(0).andNickNameEqualTo(nickname);
        List<SysUser> users = userMapper.selectByExample(userExample);
        if (users.isEmpty()) {
            return null;
        }
        return users.get(0);
    }

    @Override
    public void updateAvatar(MultipartFile avatar) {
        LoginUser loginUser = SecurityUtil.getCurrentUserDetails();
        SysUser currentUser = loginUser.getUser();
        Long userId = currentUser.getUserId();
        String path = FileUtil.uploadFile(avatar);
        SysUser user = new SysUser();
        user.setUserId(userId);
        user.setAvatar(path);
        userMapper.updateByPrimaryKeySelective(user);

        currentUser.setAvatar(path);

        String redisKey = SecurityConst.REDIS_JWT_KEY_PREFIX + userId;
        redisCache.resetCacheObject(redisKey, loginUser);

    }
}
